import path from 'node:path';
import { SYSTEM_DIR_VAR } from './config';
import { prisma } from './prisma';

interface StoreSystemInstanceConfig<Config extends object> {
  name: string;
  type: string;
  config: Config;
}

/**
 * 存储系统实例的配置
 */
export class AppStoreSystemConfig<Config extends object = object> {
  /**
   * 静态方法：解析带有系统目录变量的路径
   * @param pathWithVars - 带有变量的路径
   */
  static parseSystemPath(pathWithVars: string): string {
    let result = pathWithVars;
    Object.entries(SYSTEM_DIR_VAR).forEach(([key, value]) => {
      result = result.replace(key, value);
    });
    return path.normalize(result);
  }

  /**
   * 存储系统实例的目录配置
   * @description 一种存储类型可能存在多个实例
   * @example
   * ```js
   * 'local_server': {
   *   type: 'local',
   *   basePath: '/root/.nebulae/data/images',
   *   cachePath: '/root/.nebulae/cache/images',
   * },
   * 'nas': {
   *   type: 'local',
   *   basePath: '/nas/.nebulae/data/images',
   *   cachePath: '/nas/.nebulae/cache/images',
   * },
   * 'ali_oss': {
   *   type: 'oss',
   *   accessKeyId: 'your_access_key_id',
   *   accessKeySecret: 'your_access_key_secret',
   * ```
   */
  private _config: Record<string, StoreSystemInstanceConfig<Config>> = {};

  private async _loadConfigFromPrisma() {
    if (this.configLoaded) return;
    // 从数据库中加载存储系统实例的配置
    const storageSystemConfig = await prisma.storageSystem.findMany({
      include: {
        type: true,
      },
    });
    storageSystemConfig.forEach((item) => {
      this._config[item.id] = {
        name: item.name, // 实例名称
        type: item.type.name, // 存储系统类型
        config: (item.config ?? {}) as unknown as Config, // 存储系统配置
      };
    });
    this.configLoaded = true;
  }

  /**
   * 是否已加载配置
   * @description 避免重复加载配置
   */
  public configLoaded: boolean = false;

  /**
   * 从数据库重新加载存储系统实例的配置
   * @description 用于在配置发生变化时重新加载配置
   */
  public async reloadConfigFromPrisma() {
    this.configLoaded = false;
    await this._loadConfigFromPrisma();
  }

  public setConfig<T extends Config>(
    storeSystemInstance: string,
    config: StoreSystemInstanceConfig<T>
  ) {
    this._config[storeSystemInstance] = config;
  }

  public async getConfig<T extends Config>(storeSystemInstance: string) {
    await this._loadConfigFromPrisma();
    return this._config[storeSystemInstance] as StoreSystemInstanceConfig<T> | undefined;
  }

  public async getAllConfig<T extends Config>() {
    await this._loadConfigFromPrisma();
    return this._config as Record<string, StoreSystemInstanceConfig<T>>;
  }

  public deleteConfig(storeSystemInstance: string) {
    delete this._config[storeSystemInstance];
  }

  public clearConfig() {
    this._config = {};
  }

  public hasConfig(storeSystemInstance: string) {
    return !!this._config[storeSystemInstance];
  }

  constructor() {
    this._loadConfigFromPrisma();
  }
}
